var Application = (function () {
    let csoArray = new Array();
    let callbacks = new Map();

    function _cefSharpLoaded() {
        return typeof CefSharp != 'undefined';
    }

    async function _ensureExistsAsync(input) {
        if (!_cefSharpLoaded()) {
            return false;
        }

        if (!csoArray.includes(input)) {
            var response = await CefSharp.BindObjectAsync(input);
            if (response.Success) {
                csoArray.push(input);
                return true;
            } else {
                return false;
            }
        }

        return true;
    }

    async function _shutdownAsync() {
        if (!_cefSharpLoaded() || !await _ensureExistsAsync('applicationCso')) {
            console.log('shutdown');
            return false;
        } else {
            csoArray.length = 0;
            applicationCso.shutdown();
            return true;
        }
    }

    function _postMessage(opcode, message) {
        if (!_cefSharpLoaded()) {
            throw 'CefSharp undefined';
        }
        CefSharp.PostMessage({ Opcode: opcode, Message: message });
        
    }

    function _postMessageAsync(opcode, message) {
        return new Promise(resolve => {
            if (!_cefSharpLoaded()) {
                resolve({ Success: false, Error: 1, Message: 'CefSharp undefined' });
            }
            CefSharp.PostMessage({ Opcode: opcode, Message: message, Callback: resolve });
        });
    }

    function _registerCallback(opcode, handler) {
        if (!callbacks.has(opcode)) {
            callbacks.set(opcode, [handler]);
        } else {
            callbacks.get(opcode).push(handler);
        }
    }

    function _runMessage(opcode, message) {
        if (callbacks.has(opcode)) {
            for (const handler of callbacks.get(opcode)) {
                handler(message);
            }
        }
    }

    async function _untilAsync(condition, interval = 100) {
        return new Promise(resolve => {
            function until() {
                if (condition()) {
                    resolve();
                } else {
                    setTimeout(until, interval);
                }
            }
            setTimeout(until, 0);
        });
    }

    return {
        /**
         * CefSharp是否加载
         */
         cefSharpLoaded: _cefSharpLoaded(),
        /**
         * 确认CefSharp绑定对象存在
         * @param {string} input CefSharp绑定对象
         */
        ensureExistsAsync: _ensureExistsAsync,
        /**
         * 关闭应用
         */
        shutdownAsync: _shutdownAsync,
        /**
         * 发送消息至.Net端
         * @param {number} opcode 消息码
         * @param {object} message 消息体
         */
         postMessage: _postMessage,
        /**
         * 发送消息至.Net端,并等待返回结果
         * @param {number} opcode 消息码
         * @param {object} message 消息体
         * @returns 响应数据
         * @example const response = await postMessageAsync(opcode,message);
         */
        postMessageAsync: _postMessageAsync,
        /**
         * 注册消息回调
         * @param {number} opcode 消息码
         * @param {function} handler 消息回调
         */
         registerCallback: _registerCallback,
        /**
         * 执行消息
         * @param {number} opcode 消息码
         * @param {object} message 消息体
         */
        runMessage: _runMessage,
        /**
         * 植到条件满足
         * @param condition 条件判断函数
         * @param interval 刷新间隔(默认100ms)
         * @example await Application.untilAsync(() => new Date().getMinutes() > 50, 500);
         */
        untilAsync: _untilAsync,
    };
})();


export{
    Application
}